package com.example.mydownloader.mymodule.encrypt

import com.example.mydownloader.mymodule.log.LogUtil
import java.io.ByteArrayOutputStream
import java.io.IOException
import java.security.InvalidKeyException
import java.security.KeyFactory
import java.security.NoSuchAlgorithmException
import java.security.spec.InvalidKeySpecException
import java.security.spec.X509EncodedKeySpec
import javax.crypto.BadPaddingException
import javax.crypto.Cipher
import javax.crypto.IllegalBlockSizeException
import javax.crypto.NoSuchPaddingException


/**
 * 注意：RSA的公私密钥有格式的区分：PKCS#1 和 PKCS8
 * PKCS1 是php使用的，PKCS8为java和客户端使用。切记
 */
object RSAUtil {

    private const val RSA_ALGORITHM = "RSA"
    private const val RSA_TRANSFORM = "RSA/ECB/PKCS1Padding"

    /**
     * RSA最大加密明文大小
     */
    private const val MAX_ENCRYPT_BLOCK = 117

    /**
     * RSA最大解密密文大小
     */
    private const val MAX_DECRYPT_BLOCK = 128

    /**
     * 公钥加密
     * @param data 待加密数据
     * @param key 公钥
     * @return byte[] 加密后的数据
     * @throws NoSuchAlgorithmException
     * @throws InvalidKeySpecException
     * @throws NoSuchPaddingException
     * @throws BadPaddingException
     * @throws IllegalBlockSizeException
     * @throws InvalidKeyException
     */
    @Throws(
        NoSuchAlgorithmException::class,
        InvalidKeySpecException::class,
        NoSuchPaddingException::class,
        BadPaddingException::class,
        IllegalBlockSizeException::class,
        InvalidKeyException::class
    )
    fun encryptByPublicKey(data: ByteArray, key: ByteArray): ByteArray {
        //实例化密钥工厂
        val keyFactory = KeyFactory.getInstance(RSA_ALGORITHM)
        //初始化公钥,根据给定的编码密钥创建一个新的 X509EncodedKeySpec。
        val x509EncodedKeySpec = X509EncodedKeySpec(key)
        val publicKey = keyFactory.generatePublic(x509EncodedKeySpec)
        //数据加密
        val cipher: Cipher = Cipher.getInstance(RSA_TRANSFORM)
        cipher.init(Cipher.ENCRYPT_MODE, publicKey)
        return cipher.doFinal(data)
    }

    /**
     * 公钥加密
     *
     * @param data 待加密的数据
     * @param publicKeyByteArray ByteArray类型的公钥
     * @return ByteArray 加密后的数据
     */
    @Throws(java.lang.Exception::class)
    fun encryptByPublicKey1(data: ByteArray, publicKeyByteArray: ByteArray): ByteArray? {
        var encryptedData: ByteArray? = null
        //实例化密钥工厂
        try {
            val keyFactory = KeyFactory.getInstance(RSA_ALGORITHM)
            val x509EncodedKeySpec = X509EncodedKeySpec(publicKeyByteArray)
            val publicKey = keyFactory.generatePublic(x509EncodedKeySpec)
            val cipher: Cipher = Cipher.getInstance(RSA_TRANSFORM)
            cipher.init(Cipher.ENCRYPT_MODE, publicKey)
            val inputLength = data.size
            val out = ByteArrayOutputStream()
            var offset = 0
            var cache: ByteArray
            var i = 0
            while (inputLength - offset > 0) {
                cache = if (inputLength - offset > MAX_ENCRYPT_BLOCK) {
                    cipher.doFinal(data, offset, MAX_ENCRYPT_BLOCK)
                } else {
                    cipher.doFinal(data, offset, inputLength - offset)
                }
                out.write(cache, 0, cache.size)
                i++
                offset = i * MAX_ENCRYPT_BLOCK
            }
            encryptedData = out.toByteArray()
            out.close()
        } catch (e: NoSuchAlgorithmException) {
            LogUtil.e("$e")
        } catch (e: NullPointerException) {
            LogUtil.e("$e")
        } catch (e: InvalidKeySpecException) {
            LogUtil.e("$e")
        } catch (e: IOException) {
            LogUtil.e("$e")
        } finally {
            return encryptedData
        }
    }

    /**
     * 公钥解密
     * @param data 待解密数据
     * @param key 密钥
     * @return byte[] 解密数据
     */
    @Throws(Exception::class)
    fun decryptByPublicKey(data: ByteArray?, key: ByteArray?): ByteArray {
        //实例化密钥工厂
        val keyFactory = KeyFactory.getInstance(RSA_ALGORITHM)
        //初始化公钥
        //密钥材料转换
        val x509KeySpec = X509EncodedKeySpec(key)
        //产生公钥
        val pubKey = keyFactory.generatePublic(x509KeySpec)
        //数据解密
        val cipher: Cipher = Cipher.getInstance(RSA_TRANSFORM)
        cipher.init(Cipher.DECRYPT_MODE, pubKey)
        return cipher.doFinal(data)
    }
}